/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       town_list_window.h

	$Header: /game/town_list_window.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )
#include "town_list_window.h"

#include "adaptor_handler.h"
#include "adv_object_list_image.h"
#include "adventure_map.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_cache.h"
#include "bitmap_layer_window.h"
#include "bound_handler.h"
#include "buffer_window.h"
#include "building_traits.h"
#include "button.h"
#include "elements_of.h"
#include "enum_operations.h"
#include "external_string.h"
#include "footprint.h"
#include "memory_bitmap.h"
#include "micro_map_window.h"
#include "replace_keywords.h"
#include "scrollbar.h"
#include "terrain.h"
#include "town.h"
#include "town_drawing.h"
#include "town_list.h"
#include "town_properties.h"

t_bitmap_group_cache g_small_town_list_bitmaps( "town.small_list" );
t_bitmap_layer_cache g_small_town_marker( g_small_town_list_bitmaps, "marker" );
t_bitmap_group_cache g_town_list_bitmaps( "town.list" );
t_bitmap_layer_cache g_town_marker( g_town_list_bitmaps, "marker" );

namespace
{
    t_external_string k_micro_map_help( "location.town" );
};

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
t_town_list_window::t_town_list_window( t_screen_rect const& rect, t_window* parent, bool use_small_bitmaps )
                  : t_window( rect, k_completely_transparent, parent )
{
	if( use_small_bitmaps )
	{
		m_bitmaps = g_small_town_list_bitmaps.get();
		m_town_marker = g_small_town_marker.get();
	}
	else
	{
		m_bitmaps = g_town_list_bitmaps.get();
		m_town_marker = g_town_marker.get();
	}

	m_adventure_map = 0;
	m_towns			= 0;
	m_scrollbar		= 0;
	m_first_town	= 0;
	m_selected_town = -1;
	m_team_view		= -1;

	t_bitmap_layer const* frame = m_bitmaps->find( "frame" );
	int                   frame_height = frame->get_height();
	t_bitmap_layer const* highlight = m_bitmaps->find( "highlighted" );
	t_bitmap_layer const* built = m_bitmaps->find( "built" );
	t_screen_point        thumbnail_offset = m_bitmaps->find( "town" )->get_rect().top_left();
	t_screen_rect         map_rect = m_bitmaps->find( "map" )->get_rect();
	t_screen_point        map_offset = map_rect.top_left();
	int                   height = rect.height();
	t_screen_point        origin(0,0);
	int                   i = 0;

	m_micro_map_size = map_rect.size();

	while (origin.y + frame_height <= height)
	{
		t_item item;

		item.town = 0;
		item.button = new t_button( origin + thumbnail_offset, this );
		item.town_image = new t_buffer_window( t_screen_point(0,0), item.button );
		item.map_image = new t_micro_map_window( origin + map_offset, this );
		item.button->set_click_handler( add_2nd_argument( 
			bound_handler( *this, &t_town_list_window::select ),  i ) );
		item.button->set_double_click_handler( add_2nd_argument(
			bound_handler( *this, &t_town_list_window::double_click ), i ) );

		item.normal_border = new t_bitmap_layer_window( frame, origin, this );
		item.highlight_border = new t_bitmap_layer_window( highlight, origin, this );
		item.highlight_border->set_visible( false );

		if( built )
		{
			item.built_checkmark_image = new t_bitmap_layer_window( built, origin, this );
			item.built_checkmark_image->set_visible( false );
		}

		m_items.push_back( item );
		origin.y += frame_height + 2;
		i++;
	}
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
t_town_list_window::~t_town_list_window()
{
	if (m_towns != 0)
		m_towns->detach( this );
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::attach( t_scrollbar* scrollbar )
{
	m_scrollbar = scrollbar;
	if (scrollbar == 0)
		return;

	scrollbar->set_handler( bound_handler( *this, &t_town_list_window::scroll_list ) );
	set_scrollbar();
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::detach()
{
	m_towns = 0;
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::inserted( int index )
{
	if (index < m_first_town)
		m_first_town++;
	if (index < m_selected_town)
		m_selected_town++;
	m_town_images.insert( m_town_images.begin() + index, t_adv_object_list_image() );
	set_scrollbar();
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::removed( int index )
{
	if (index <= m_first_town && m_first_town > 0)
		m_first_town--;
	if (index == m_selected_town)
		m_selected_town = -1;
	if (index <= m_selected_town && m_selected_town >= 0)
		m_selected_town--;
	m_town_images.erase( m_town_images.begin() + index );
	set_scrollbar();
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::set_town_list( t_town_list* list, int team_view )
{
	if (list == m_towns)
		return;

	if (m_towns != 0)
		m_towns->detach( this );

	list->attach( this );
	m_towns = list;
	m_team_view = team_view;
	m_town_images.clear();
	m_town_images.resize( list->size() );
	m_first_town = 0;
	m_selected_town = -1;
	set_scrollbar();
	update();
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::select_town( t_town* town )
{
	if (m_towns == NULL || m_towns->empty())
		return;

	if (m_selected_town >= 0 && (*m_towns)[m_selected_town].get() == town)
		return;

	int i;

	i = m_towns->size();
	while (i--)
	{
		if ((*m_towns)[i].get() == town)
			break;
	}
	if (i >= 0)
	{
		if (i < m_first_town)
		{
			m_first_town = i;
			update();
			set_scrollbar();
		}
		if (i >= m_first_town + m_items.size())
		{
			m_first_town = i - m_items.size() + 1;
			update();
			set_scrollbar();
		}
	}

	set_highlight( i );
}

void t_town_list_window::set_map( t_adventure_map const& map )
{
	m_adventure_map = &map;
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::update()
{
	assert( m_adventure_map != 0 );

	int i;
	int limit;

	limit = 0;
	if (m_towns != 0)
		limit = m_towns->size() - m_first_town;
	if (limit > m_items.size())
		limit = m_items.size();

	for (i = 0; i < limit; i++)
	{
		t_town*			   town = (*m_towns)[i + m_first_town];
		t_item&			   item = m_items[i];
		t_adv_object_list_image& image =  m_town_images[ i + m_first_town ];
	    t_level_map_point_2d town_point = town->get_position();

		image.set_town( town );
		item.town_image->set_bitmap( image.get_bitmap() );

		item.map_image->set_renderer( &image.get_map_renderer( *m_adventure_map, m_team_view, m_micro_map_size, m_town_marker ) );
		item.button->set_released_image( item.town_image );
		item.button->set_visible( true );
		item.button->set_help_balloon_text( town->get_name() );
		item.map_image->set_help_balloon_text( replace_keywords( k_micro_map_help, 
											   "%town_name", town->get_name() ) );
		item.map_image->set_visible( true );

		if( item.built_checkmark_image )
		{
			if( town->has_built() )
				item.built_checkmark_image->set_visible( true );
			else
				item.built_checkmark_image->set_visible( false );
		}
	}
	while (i < m_items.size())
	{
		t_item& item = m_items[i];

		item.town = 0;
		item.button->set_visible( false );
		item.town_image->set_visible( false );
		item.map_image->set_renderer( 0 );
		item.map_image->set_visible( false );
		item.built_checkmark_image->set_visible( false );
		i++;
	}
	set_highlight( m_selected_town );
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::double_click( t_button* button, int result )
{
	if (m_towns == 0)
		return;
	if (result + m_first_town >= m_towns->size())
		return;

	m_double_click_handler( (*m_towns)[m_first_town + result] );
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::select( t_button* button, int result )
{
	if (m_towns == 0)
		return;
	if (result + m_first_town >= m_towns->size())
		return;

	set_highlight( m_first_town + result );
	m_select_handler( (*m_towns)[m_selected_town] );
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::set_scrollbar()
{
	int maximum;

	if (m_scrollbar == 0)
		return;

	if (m_towns == 0)
		maximum = 0;
	else
	{
		maximum = m_towns->size() - m_items.size();
		if (maximum < 0)
			maximum = 0;
	}
	m_scrollbar->set_limits( 0, maximum );
	m_scrollbar->set_position( m_first_town );
	m_scrollbar->set_visible( is_visible() && maximum > 0 );
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::set_highlight( int index )
{
	int i;

	m_selected_town = index;
	index = m_selected_town - m_first_town;
	for (i = 0; i < m_items.size(); i++)
	{
		t_item& item = m_items[i];

		item.normal_border->set_visible( i != index );
		item.highlight_border->set_visible( i == index );
	}
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::scroll_list( t_scrollbar* scrollbar, int first_value )
{
	if (m_first_town == first_value)
		return;

	m_first_town = first_value;
	update();
}

// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
void t_town_list_window::move_selection_and_select( int step_size, bool wrap_selection )
{
	move_selection( step_size, wrap_selection );
	select( 0, m_selected_town - m_first_town );
}

// ----------------------------------------------------------------------
// Move the selection N slots from its current position in the list
// ----------------------------------------------------------------------
t_town * t_town_list_window::move_selection( int step_size, bool wrap_selection )
{
	if (!m_towns || m_towns->empty() )
		return 0;
	
	int index = m_selected_town + step_size;

	if( index < 0 )
	{
		if( wrap_selection )
			index = m_towns->size() - 1;
		else
			index = 0;
	}
	if( index >= m_towns->size() )
	{
		if( wrap_selection )
			index = 0;
		else
			index = m_towns->size() - 1;
	}

	t_town* town = (*m_towns)[index].get();
	select_town( town );

	return (*m_towns)[m_selected_town];
}

// ----------------------------------------------------------------------
// display a list of towns
// ----------------------------------------------------------------------
void t_town_list_window::on_visibility_change()
{
	t_window::on_visibility_change();
	if ( m_scrollbar != 0 )
		m_scrollbar->set_visible( is_visible() && m_towns != 0 && m_towns->size() > m_items.size() );
}
